import constraint_horizontal_texture from '@app-cad/assets/constraint_images/horizontal.png';
import constraint_vertical_texture from '@app-cad/assets/constraint_images/vertical.png';
import constraint_collinear_texture from '@app-cad/assets/constraint_images/collineation.png';
import constraint_concentric_texture from '@app-cad/assets/constraint_images/concentric.png';
import constraint_equal_texture from '@app-cad/assets/constraint_images/equality.png';
import constraint_fixed_texture from '@app-cad/assets/constraint_images/fixed.png';
import constraint_midPoint_texture from '@app-cad/assets/constraint_images/mid_point.png';
import constraint_parallel_texture from '@app-cad/assets/constraint_images/parallel.png';
import constraint_perpendicularity_texture from '@app-cad/assets/constraint_images/perpendicular.png';
import constraint_pointInObj_texture from '@app-cad/assets/constraint_images/pointInObj.png';
import constraint_tangency_texture from '@app-cad/assets/constraint_images/tangency.png';
import constraint_symmetric_texture from '@app-cad/assets/constraint_images/symmetric.png';

import {
  CanvasTexture,
  Object3D,
  Sprite,
  SpriteMaterial,
  TextureLoader,
} from 'three-legacy';
import { ConstraintTag } from '@app-cad/common/utils/sketchTools/ConstraintIconRenderer';
import { ConstraintType } from '@amcax/base';

const textures: Partial<Record<ConstraintType, string>> = {
  [ConstraintType.Horizontal]: constraint_horizontal_texture,
  [ConstraintType.Vertical]: constraint_vertical_texture,
  [ConstraintType.Parallel]: constraint_parallel_texture,
  [ConstraintType.Perpendicular]: constraint_perpendicularity_texture,
  [ConstraintType.Tangent]: constraint_tangency_texture,
  [ConstraintType.Equal]: constraint_equal_texture,
  [ConstraintType.Coincident]: constraint_pointInObj_texture,
  [ConstraintType.PointOnObject]: constraint_pointInObj_texture,
  [ConstraintType.Fix]: constraint_fixed_texture,
  [ConstraintType.Collinear]: constraint_collinear_texture,
  [ConstraintType.Concentric]: constraint_concentric_texture,
  [ConstraintType.MidPoint]: constraint_midPoint_texture,
  [ConstraintType.Symmetric]: constraint_symmetric_texture,
};

export class ConstraintIcon extends Object3D {
  // 比CSPoint默认高1
  static iconRenderOrder = 1000;
  static hoverModoalRenderOrder = 1001;
  static hoveredRenderOrder = 1002;

  static materialMap = new Map<ConstraintType, SpriteMaterial>();
  static hoverColor = '#C7D0FF';
  static selectColor = '#00D4FF';
  static defaultBgColor = '#C7D0FF';
  static hoverMaterial: SpriteMaterial;
  static selectMaterial: SpriteMaterial;
  static defaultBgMaterial: SpriteMaterial;

  static resourceInited = false;
  static textureLoader = new TextureLoader();
  static async initResource() {
    if (ConstraintIcon.resourceInited) {
      return Promise.resolve();
    }
    await Promise.all(
      Object.keys(textures).map(
        (type) =>
          new Promise((resolve) => {
            // 加载失败也不阻塞初始化，后续依然可以让CSPoint尝试加载
            const texture = ConstraintIcon.textureLoader.load(
              textures[type],
              resolve,
              null,
              resolve,
            );

            ConstraintIcon.materialMap.set(
              Number(type),
              new SpriteMaterial({
                map: texture,
                depthTest: false,
              }),
            );
          }),
      ),
    );

    // 用 canvas 绘制 select 遮罩材质

    ConstraintIcon.selectMaterial = ConstraintIcon.getColoredTexture(
      ConstraintIcon.selectColor,
    );

    ConstraintIcon.hoverMaterial = ConstraintIcon.getColoredTexture(
      ConstraintIcon.hoverColor,
    );

    ConstraintIcon.defaultBgMaterial = ConstraintIcon.getColoredTexture(
      ConstraintIcon.defaultBgColor,
    );

    ConstraintIcon.resourceInited = true;
  }

  static getColoredTexture(color: string) {
    const canvas = document.createElement('canvas');
    canvas.height = 32;
    canvas.width = 32;
    const context = canvas.getContext('2d');
    context.fillStyle = color;
    context.fillRect(0, 0, canvas.width, canvas.height);
    const texture = new CanvasTexture(canvas);

    return new SpriteMaterial({
      map: texture,
      depthTest: false,
      transparent: true,
      opacity: 0.5,
    });
  }

  sprite: Sprite;
  defaultBgSprite: Sprite;
  selectModalSprite: Sprite;
  hoverModalSprite: Sprite;

  // 两种状态允许叠加，叠加的情况下以hover为准
  hovered = false;
  selected = false;

  constructor(public constraintTag: ConstraintTag) {
    super();

    // 添加默认背景
    this.defaultBgSprite = new Sprite(ConstraintIcon.defaultBgMaterial);
    this.defaultBgSprite.renderOrder = ConstraintIcon.iconRenderOrder - 1;
    this.add(this.defaultBgSprite);

    this.sprite = new Sprite(
      ConstraintIcon.materialMap.get(constraintTag.constraint.type),
    );
    this.sprite.renderOrder = ConstraintIcon.iconRenderOrder;
    this.add(this.sprite);
  }

  private renderState() {
    this.remove(this.selectModalSprite);
    this.selectModalSprite = null;
    this.remove(this.hoverModalSprite);
    this.hoverModalSprite = null;
    this.sprite.renderOrder = ConstraintIcon.iconRenderOrder;

    // 默认状态下显示背景
    if (!this.selected && !this.hovered) {
      this.defaultBgSprite.visible = true;
    } else {
      this.defaultBgSprite.visible = false;
    }

    if (this.selected) {
      this.selectModalSprite = new Sprite(ConstraintIcon.selectMaterial);
      this.selectModalSprite.renderOrder = ConstraintIcon.iconRenderOrder;
    }

    if (this.hovered) {
      this.sprite.renderOrder = ConstraintIcon.hoveredRenderOrder;

      if (!this.selected) {
        this.hoverModalSprite = new Sprite(ConstraintIcon.hoverMaterial);
        this.hoverModalSprite.renderOrder =
          ConstraintIcon.hoverModoalRenderOrder;
        this.hoverModalSprite?.scale?.set(1.2, 1.2, 1);
      }

      if (this.selectModalSprite != null) {
        this.selectModalSprite.renderOrder = ConstraintIcon.hoveredRenderOrder;
      }
    }

    if (this.selected) {
      if (this.selectModalSprite) {
        this.add(this.selectModalSprite);
      }
    } else {
      if (this.hoverModalSprite) {
        this.add(this.hoverModalSprite);
      }
    }
  }

  resetState() {
    this.hovered = false;
    this.selected = false;
    this.renderState();
  }

  hover(hovered = true) {
    this.hovered = hovered;
    this.renderState();
  }

  select(selected = true) {
    this.selected = selected;
    this.renderState();
  }
}
